home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / httpproxy / src / httpfetch.c < prev    next >
C/C++ Source or Header  |  1996-08-20  |  9KB  |  393 lines

  1. /*(( "Header" */
  2. /*
  3.  * $Id: httpfetch.c,v 1.5 1996/08/11 22:25:15 mshopf Exp mshopf $
  4.  *
  5.  * (c) 1995-96 Matthias Hopf
  6.  *
  7.  * The usual fetchurl tool, with some extensions for httpproxy.
  8.  */
  9.  
  10. /*
  11.  * $Log: httpfetch.c,v $
  12.  * Revision 1.5  1996/08/11  22:25:15  mshopf
  13.  * reworked debug messages.
  14.  *
  15.  * Revision 1.4  1996/07/17  16:42:42  mshopf
  16.  * small bug fix.
  17.  *
  18.  * Revision 1.3  1996/06/03  04:13:31  mshopf
  19.  * support for net errors.
  20.  *
  21.  * Revision 1.2  1996/05/15  01:07:58  mshopf
  22.  * small bug fix.
  23.  *
  24.  * Revision 1.1  1996/04/16  04:39:29  mshopf
  25.  */
  26.  
  27.  
  28. /*)) */
  29. /*(( "Includes & Konstanten" */
  30.  
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <errno.h>
  35. #include <string.h>
  36.  
  37. #include <proto/exec.h>
  38. #include <proto/dos.h>
  39.  
  40. #include "net.h"
  41. #include "debug.h"
  42.  
  43. #define  BUFSIZE        1024    /* don't make this one too large (it's on the stack) */
  44.  
  45. #define  MAX_HOSTNAMELEN 128    /* including port number specifiers */
  46. #define  MAX_URLLEN      1024   /* maximum size of URL request */
  47. #define  MAX_OVERHEAD    128    /* maximum size of protocol overhead */
  48.  
  49. #define  DEFAULT_HTTPPORT  80
  50. #define  DEFAULT_PROXYPORT 8080
  51. #define  DEFAULT_RETRIES   1
  52. #define  DEFAULT_HEADER    FALSE
  53. #define  DEFAULT_SERVICE   FALSE
  54.  
  55. /*)) */
  56. /*(( "Global Variables" */
  57.  
  58. long   __oslibversion      = 37;
  59. const  char *Version       = "httpfetch/1.0";
  60.  
  61. #ifdef DEBUG
  62. int DebugLevel = -1;
  63. #endif
  64.  
  65. static netmethods_t *Net   = NULL;
  66. static int  InSocket       = -1;
  67. static FILE *OutStream     = stdout;
  68. static struct RDArgs *RDArgs = NULL;
  69.  
  70. static char *Template      = "URL/A,FROM=PROXY/K,TO=FILE,RETRIES=RETRY/N/K,HEADER=FULL/S,SERVICE/S,DISCARD=QUIET/S";
  71. #define arg_url     ((char *) (RetArray[0]))
  72. #define arg_from    ((char *) (RetArray[1]))
  73. #define arg_to      ((char *) (RetArray[2]))
  74. #define arg_retries (RetArray[3] ? *((long *) (RetArray[3])) : DEFAULT_RETRIES)
  75. #define arg_header  ((long)   (RetArray[4]))
  76. #define arg_service ((long)   (RetArray[5]))
  77. #define arg_discard ((long)   (RetArray[6]))
  78.  
  79. /*)) */
  80.  
  81. /*(( "ExitAll () / ExitErr ()" */
  82.  
  83. /* Close everything and return */
  84.  
  85. void ExitAll (int Ret)
  86. {
  87.     if (Net && InSocket >= 0)
  88.     Net->close (InSocket);
  89.     InSocket = -1;
  90.     if (Net)
  91.     Net->exit ();
  92.     Net       = NULL;
  93.     if (OutStream && OutStream != stdout)
  94.     fclose (OutStream);
  95.     OutStream = NULL;
  96.     if (RDArgs)
  97.     FreeArgs (RDArgs);
  98.     RDArgs    = NULL;
  99.     exit (Ret);
  100. }
  101.  
  102. /* Print errormessage and exit with 10 */
  103.  
  104. void ExitErr (const char *Msg)
  105. {
  106.     if (errno)
  107.     {
  108.     if (Net)
  109.         fprintf (stderr, "%s: %s\n", Msg, Net->strerror (errno));
  110.     else
  111.         perror (Msg);
  112.     }
  113.     else
  114.     fprintf (stderr, "%s\n", Msg);
  115.     ExitAll (10);
  116. }
  117.  
  118. /*)) */
  119. /*(( "SendRequest ()" */
  120.  
  121. /* send request to Socket fd */
  122.  
  123. int SendRequest (int Fd, char *Req)
  124. {
  125.     int Len;
  126.     Len = strlen (Req);
  127.     return (Net->write (Fd, Req, Len) == Len);
  128. }
  129.  
  130. /*)) */
  131. /*(( "SkipHeader ()" */
  132.  
  133. /* skip header data */
  134.  
  135. int SkipHeader (int Fd)
  136. {
  137.     char Buffer [BUFSIZE+1];
  138.     char *c, *Pos;
  139.     int  i;
  140.  
  141.     Pos = Buffer;
  142.     for (;;)
  143.     {
  144.         /* read partial header */
  145.     if ( (i = Net->read (Fd, Pos, (int) (BUFSIZE - (Buffer - Pos)))) <= 0)
  146.         return FALSE;
  147.     Pos [i] = '\0';
  148.         /* check for header end and flush the rest into the output stream */
  149.     if ( (c = strstr (Buffer, "\r\n\r\n")) || (c = strstr (Buffer, "\n\r\n\r")) )
  150.     {
  151.         if (OutStream && Pos + i - c - 4 > 0)
  152.         return ((int) fwrite (c + 4, (size_t) (Pos + i - c - 4), 1, OutStream));    /* fwrite returns number of blocks=1 on success... */
  153.         return TRUE;
  154.     }
  155.     if ( (c = strstr (Buffer, "\r\r")) || (c = strstr (Buffer, "\n\n")) )
  156.     {
  157.         if (OutStream && Pos + i - c - 2 > 0)
  158.         return ((int) fwrite (c + 2, (size_t) (Pos + i - c - 2), 1, OutStream));    /* fwrite returns number of blocks=1 on success... */
  159.         return TRUE;
  160.     }
  161.         /* header not yet done - check end and skip back until we're save for flushing */
  162.     if (Pos [i-1] != '\r' && Pos [i-1] != '\n')
  163.         Pos = Buffer;
  164.     else
  165.     {
  166.         c = &Pos [i-2];
  167.         while (c >= Buffer)
  168.         if (*c != '\r' && *c != '\n')
  169.             break;
  170.         else
  171.             c--;
  172.         /* move remaining '\n' and '\r's to beginning of buffer */
  173.         memmove (Buffer, c + 1, (size_t) (Pos + i - c - 1));
  174.         Pos = Buffer + (Pos + i - c - 1);
  175.     }
  176.     }
  177.     /* NOTREACHED */
  178. }
  179.  
  180. /*)) */
  181. /*(( "ReceiveData ()" */
  182.  
  183. /* save received data */
  184.  
  185. int ReceiveData (int Fd)
  186. {
  187.     char Buffer [BUFSIZE];
  188.     int i;
  189.  
  190.     for (;;)
  191.     {
  192.     if ( (i = Net->read (Fd, Buffer, BUFSIZE)) <= 0)
  193.         return (i < 0 ? FALSE : TRUE);
  194.     if (OutStream)
  195.         if (fwrite (Buffer, i, 1, OutStream) != 1)
  196.         return FALSE;
  197.     }
  198.     /* NOTREACHED */
  199. }
  200.  
  201. /*)) */
  202. /*(( "MakeRequest ()" */
  203.  
  204. void MakeRequest (char *Req, char *Url)
  205. {
  206.     int Len;
  207.  
  208.     Len  = strlen (Req);
  209.     Req += Len;
  210.     Len += strlen (Url);
  211.     if (Len > MAX_URLLEN)
  212.     ExitErr ("URL too long error");
  213.     strcpy (Req, Url);
  214.     Req += strlen (Req);
  215.     sprintf (Req, " HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n\r\n", Version);
  216. }
  217.  
  218. /*)) */
  219. /*(( "MakeService ()" */
  220.  
  221. /* Make a httpproxy service request */
  222.  
  223. void MakeService (char *Req, char *Service)
  224. {
  225.     int Len;
  226.  
  227.     Len = strlen (Req);
  228.     Req += Len;          /* skip protocol part and GET command */
  229.     Len += strlen (Service);
  230.     if (Len > MAX_URLLEN)
  231.     ExitErr ("Service too long error");
  232.     strcpy (Req, "http://proxy.../");
  233.     Req += 16;
  234.     strcpy (Req, Service);
  235.     Req += strlen (Req);
  236.     sprintf (Req, " HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n\r\n", Version);
  237. }
  238. /*)) */
  239. /*(( "Action ()" */
  240.  
  241. /* Interprete Arguments */
  242. /* RetArray has to be exactly written like this in order to have the arg_* macros working */
  243.  
  244. void Action (long *RetArray)
  245. {
  246.     static char Request [MAX_URLLEN + MAX_OVERHEAD];
  247.     char Host [MAX_HOSTNAMELEN];
  248.     int  Port = DEFAULT_HTTPPORT;
  249.     char *c;
  250.     int  i;
  251.  
  252.     Host [0] = '\0';
  253.  
  254.     if (arg_to && arg_discard)
  255.     ExitErr ("don't specify both TO=FILE and DISCARD=QUIET");
  256.  
  257.     /* - destination file */
  258.     if (arg_to)
  259.     if (! (OutStream = fopen (arg_to, "wb+")))
  260.         ExitErr ("can't open file");
  261.     if (arg_discard)
  262.     OutStream = NULL;
  263.  
  264.     /* - proxy host, url and service */
  265.     if (arg_from)
  266.     {                                                      /* get in proxy mode */
  267.     Port = DEFAULT_PROXYPORT;
  268.     strncpy (Host, arg_from, MAX_HOSTNAMELEN-1);
  269.     Host [MAX_HOSTNAMELEN-1] = '\0';
  270.     if ( (c = strchr (Host, ':')) )
  271.     {
  272.         *c = '\0';
  273.         Port = atoi (c+1);
  274.     }
  275.     strcpy (Request, "GET ");
  276.     if (arg_service)
  277.         MakeService (Request, arg_url);
  278.     else
  279.         MakeRequest (Request, arg_url);
  280.     }
  281.     else
  282.     {
  283.     if (! arg_service)
  284.     {
  285.         /* check protocol name for 'http://' */
  286.         if (strncmp (arg_url, "http://", 7) != 0)
  287.         ExitErr ("invalid URL");
  288.         strcpy  (Request, "GET ");
  289.         /* now get host name and port */
  290.         strncpy (Host, arg_url + 7, MAX_HOSTNAMELEN-1);      /* ok, that's too much, but who cares */
  291.         Host [MAX_HOSTNAMELEN-1] = '\0';
  292.         if ( (c = strchr (Host, '/')) )             /* get hostname and port */
  293.         *c = '\0';
  294.         if ( (c = strchr (Host, ':')) )
  295.         {
  296.         *c = '\0';
  297.         Port = atoi (c+1);
  298.         }
  299.         if (Host [0] == '\0')                        /* no host??? */
  300.         ExitErr ("invalid URL");
  301.         /* get local object name */
  302.         if ( (c = strchr (arg_url + 7, '/')) )
  303.         MakeRequest (Request, c);
  304.         else
  305.         MakeRequest (Request, "/");
  306.     }
  307.     else
  308.     {
  309.         strcpy  (Host, "localhost");            /* on service we'll address our local proxy */
  310.         Port = DEFAULT_PROXYPORT;
  311.         strcpy (Request, "GET ");
  312.         MakeService (& Request [4], arg_url);
  313.     }
  314.     }
  315.  
  316.     for (i = 0; i < arg_retries; i++)
  317.     {
  318.     if (i)
  319.         Delay (50);          /* one second delay after first try */
  320.     if ( (InSocket = Net->open (Host, Port)) < 0)
  321.         continue;
  322.     if (! SendRequest (InSocket, Request))
  323.     {
  324.         Net->close (InSocket);
  325.         InSocket = -2;
  326.         continue;
  327.     }
  328.     break;
  329.     }
  330.     switch (InSocket) {
  331.     case -1:
  332.     ExitErr ("can't contact host");
  333.     case -2:
  334.     ExitErr ("failed sending request");
  335.     }
  336.  
  337.     if (OutStream && ! arg_header)
  338.     if (! SkipHeader (InSocket))
  339.         ExitErr ("failed while receiving header");
  340.     if (! ReceiveData (InSocket))
  341.     ExitErr ("failed while receiving data");
  342.     Net->close (InSocket);
  343.     InSocket = -1;
  344. }
  345.  
  346. /*)) */
  347. /*(( "main ()" */
  348.  
  349. /* main function */
  350.  
  351. void main (int argc, char *argv[])
  352. {
  353.     netmethods_t *NetList[] = { &NetAmiTCP, &NetAS225, NULL }; /* all available net protocolls */
  354.     netmethods_t **TestNet;
  355.     long RetArray[] = { 0, 0, 0, 0, 0, 0, 0 };
  356.  
  357.     /* get net handler */
  358.     for (TestNet = NetList; (Net = *TestNet); TestNet++)
  359.     if (Net->init (TRUE))                 /* check for opening in blocking mode */
  360.         break;
  361.  
  362.     if (! Net)
  363.     {
  364.     fprintf (stderr, "Couldn't open network protocol handler - perhaps the network stack is not running.\n"
  365.              "Available network protocol handlers:\n");
  366.     for (TestNet = NetList; (Net = *TestNet); TestNet++)
  367.         fprintf (stderr, "%s\n", Net->Descr);
  368.     ExitAll (20);
  369.     }
  370.  
  371.     /* Get arguments */
  372.     if (! (RDArgs = ReadArgs (Template, RetArray, NULL)))
  373.     {
  374.     fprintf (stderr, "%s\n"
  375.          "\tURL:     The URL to be retrieved.\n"
  376.          "\tFROM:    Proxy host (and :port) to be used for fetching.\n"
  377.          "\tTO:      Filename for the resulting document.\n"
  378.          "\tRETRIES: The number of retries after one second delay each.\n"
  379.          "\tHEADER:  The response header is saved, too.\n"
  380.          "\tSERVICE: Url specifies the proxy service to be done.\n"
  381.          "\tDISCARD: Discard received data.\n",
  382.          Template);
  383.     ExitAll (10);
  384.     }
  385.  
  386.     Action (RetArray);
  387.  
  388.     ExitAll (0);
  389. }
  390.  
  391. /*)) */
  392.  
  393.